package com.project.seckill.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.seckill.entity.Product;
import com.project.seckill.entity.ProductStockLog;
import com.project.seckill.mapper.ProductMapper;
import com.project.seckill.service.ProductService;
import com.project.seckill.service.ProductStockLogService;
import com.project.seckill.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private ProductStockLogService productStockLogService;

    @Autowired
    private ProductMapper productMapper;


    @Override
    public String generateToken(Integer userId, Long productId) {
        if (userId == null || productId == null) {
            return null;
        }
        if (redisUtils.exists("product:stock:over:" + productId)) {
            return null;
        }
        QueryWrapper<Product> queryWrapper = new QueryWrapper<Product>();
        queryWrapper.eq("id", productId);
        Product product = this.getOne(queryWrapper);
        if (product == null) {
            return null;
        }

        if (redisUtils.decrement("product:stock:" + productId, 1L) < 0) {
            return null;
        }
        String key = "product:token:" + userId + ":" + productId;
        String token = UUID.randomUUID().toString().replace("-", "");
        redisUtils.set(key, token, 10L, TimeUnit.MINUTES);
        return token;
    }

    @Override
    public void getProductById(Long productId) {
        Product product = this.baseMapper.selectById(productId);
        if (product != null) {
            redisUtils.set("product:stock:" + productId, product.getStock());
        }

    }

    @Override
    public boolean decreaseStockInCache(Long productId) {
        String key = "product:stock:" + productId;
        Long result = redisUtils.decrement(key, 1L);
        if (result < 0) {
            this.increaseStockInCache(productId);
        } else if (result == 0) {
            redisUtils.set("product:stock:over:" + productId, 1);
        }
        return result >= 0;
    }

    @Override
    @Transactional
    public ProductStockLog createProductStockLog(Long productId, int num) {
        ProductStockLog log = new ProductStockLog();
        log.setId(UUID.randomUUID().toString().replace("-", ""));
        log.setProductId(productId);
        log.setNum(num);
        log.setStatus(0);
        productStockLogService.save(log);
        return log;
    }

    @Override
    @Transactional
    public void increaseSales(Long id, int num) {

        Product product = this.getById(id);
        LambdaUpdateWrapper<Product> updateWrapper = new UpdateWrapper<Product>().lambda();
        updateWrapper.setSql("stock=stock-" + num);
        updateWrapper.eq(Product::getId,id);
        this.update(updateWrapper);
    }

    public boolean increaseStockInCache(Long productId) {
        String key = "product:stock:" + productId;
        redisUtils.increment(key, 1L);
        return true;
    }
}
